package top.ieei.demo.openpgp;


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Iterator;

import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedDataList;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
import org.bouncycastle.openpgp.PGPMarker;
import org.bouncycastle.openpgp.PGPOnePassSignature;
import org.bouncycastle.openpgp.PGPOnePassSignatureList;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.bouncycastle.openpgp.PGPSignatureList;
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.bouncycastle.util.io.Streams;

/**
 * PGP加密解密验签工具<br/>
 * @author Forrest(xiecongshu)
 * @since 2017年5月16日
 */
public class PGP
{
	/**
	 * 加密算法
	 */
	private int encryptAlgorithm = PGPEncryptedData.AES_256;

	/**
	 * 签名算法
	 */
	private int signAlgorithm = PGPUtil.SHA256;

	/**
	 * 默认构造函数
	 */
	public PGP() {

	}

	/**
	 * 构造函数
	 * @param encryptAlgorithm 加密算法
	 * @param signAlgorithm 签名算法
	 */
	public PGP(int encryptAlgorithm, int signAlgorithm) {
		this.encryptAlgorithm = encryptAlgorithm;
		this.signAlgorithm = signAlgorithm;
	}

	/**
	 * 压缩文件
	 * @param fileName
	 * @param algorithm
	 * @return
	 * @throws IOException
	 * @author Forrest(xiecongshu)
	 * @since 2017年5月17日
	 */
	private static byte[] compressFile(String fileName, int algorithm) throws IOException
	{
		ByteArrayOutputStream bOut = new ByteArrayOutputStream();
		PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(algorithm);
		PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName));
		comData.close();
		return bOut.toByteArray();
	}

	/**
	 * Search a secret key ring collection for a secret key corresponding to keyID if it exists.
	 * @param pgpSec a secret key ring collection.
	 * @param keyID keyID we want.
	 * @param pass passphrase to decrypt secret key with.
	 * @return the private key.
	 * @throws PGPException
	 * @throws NoSuchProviderException
	 */
	private PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass)
			throws PGPException, NoSuchProviderException
	{
		PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);

		if (pgpSecKey == null)
		{
			return null;
		}

		return pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass));
	}

	/**
	 * 读取公钥
	 * @param fileName
	 * @return
	 * @throws IOException
	 * @throws PGPException
	 * @author Forrest(xiecongshu)
	 * @since 2017年5月17日
	 */
	private PGPPublicKey readPublicKey(String fileName) throws IOException, PGPException
	{
		InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
		PGPPublicKey pubKey = readPublicKey(keyIn);
		keyIn.close();
		return pubKey;
	}

	/**
	 * A simple routine that opens a key ring file and loads the first available key suitable for encryption.
	 * @param input data stream containing the public key data
	 * @return the first public key found.
	 * @throws IOException
	 * @throws PGPException
	 */
	private PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException
	{
		PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input),
				new JcaKeyFingerprintCalculator());

		//
		// we just loop through the collection till we find a key suitable for encryption, in the real
		// world you would probably want to be a bit smarter about this.
		//

		Iterator<PGPPublicKeyRing> keyRingIter = pgpPub.getKeyRings();
		while (keyRingIter.hasNext())
		{
			PGPPublicKeyRing keyRing = (PGPPublicKeyRing) keyRingIter.next();

			Iterator<PGPPublicKey> keyIter = keyRing.getPublicKeys();
			while (keyIter.hasNext())
			{
				PGPPublicKey key = (PGPPublicKey) keyIter.next();

				if (key.isEncryptionKey())
				{
					return key;
				}
			}
		}

		throw new IllegalArgumentException("Can't find encryption key in key ring.");
	}

	/**
	 * 读取私钥
	 * @param fileName
	 * @return
	 * @throws IOException
	 * @throws PGPException
	 * @author Forrest(xiecongshu)
	 * @since 2017年5月31日
	 */
	private PGPSecretKey readSecretKey(String fileName) throws IOException, PGPException
	{
		InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
		PGPSecretKey secKey = readSecretKey(keyIn);
		keyIn.close();
		return secKey;
	}

	/**
	 * A simple routine that opens a key ring file and loads the first available key suitable for signature generation.
	 * @param input stream to read the secret key ring collection from.
	 * @return a secret key.
	 * @throws IOException on a problem with using the input stream.
	 * @throws PGPException if there is an issue parsing the input stream.
	 */
	private PGPSecretKey readSecretKey(InputStream input) throws IOException, PGPException
	{
		PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(input),
				new JcaKeyFingerprintCalculator());

		//
		// we just loop through the collection till we find a key suitable for encryption, in the real
		// world you would probably want to be a bit smarter about this.
		//

		Iterator<PGPSecretKeyRing> keyRingIter = pgpSec.getKeyRings();
		while (keyRingIter.hasNext())
		{
			PGPSecretKeyRing keyRing = (PGPSecretKeyRing) keyRingIter.next();

			Iterator<PGPSecretKey> keyIter = keyRing.getSecretKeys();
			while (keyIter.hasNext())
			{
				PGPSecretKey key = (PGPSecretKey) keyIter.next();

				if (key.isSigningKey())
				{
					return key;
				}
			}
		}
		throw new IllegalArgumentException("Can't find signing key in key ring.");
	}

	/**
	 * 解密文件
	 * @param encryptedFile
	 * @param publicKeyFile
	 * @param privateKeyFile
	 * @param passphrase
	 * @param outFile
	 * @author Forrest(xiecongshu)
	 * @since 2017年5月17日
	 */
	public void decrypt(File encryptedFile, File publicKeyFile, File privateKeyFile, String passphrase, File outFile)
	{
		if (!encryptedFile.exists())
		{
			throw new IllegalArgumentException("Encrypted file is not exists.");
		}
		if (!publicKeyFile.exists())
		{
			throw new IllegalArgumentException("Public Key file is not exists.");
		}
		if (!privateKeyFile.exists())
		{
			throw new IllegalArgumentException("Private Key file is not exists.");
		}
		if (passphrase == null)
		{
			throw new IllegalArgumentException("Private Key's passphrase is null.");
		}
		InputStream fileIn = null;
		InputStream dataInput = null;
		OutputStream fOut = null;
		try
		{
			PGPOnePassSignatureList signList = null;
			PGPEncryptedDataList dataList = null;
			PGPCompressedData compressedData = null;
			PGPLiteralData literalData = null;
			fileIn = PGPUtil.getDecoderStream(new FileInputStream(encryptedFile));
			JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(fileIn);
			Object obj = pgpFact.nextObject();
			if (obj == null)
			{
				fileIn = new FileInputStream(encryptedFile);
				fOut = new FileOutputStream(outFile);
				Streams.pipeAll(fileIn, fOut);
				System.out.println("Message decryption complete.");
				encryptedFile.delete();
				return;
			}
			if (obj instanceof PGPMarker)
			{
				obj = pgpFact.nextObject();
			}
			// 如果是压缩数据
			if (obj instanceof PGPCompressedData)
			{
				compressedData = (PGPCompressedData) obj;
				pgpFact = new JcaPGPObjectFactory(compressedData.getDataStream());
				obj = pgpFact.nextObject();
				if (obj instanceof PGPOnePassSignatureList)
				{
					signList = (PGPOnePassSignatureList) obj;
					handelSignatureList(signList, pgpFact, publicKeyFile, privateKeyFile, passphrase, outFile);
				}
			}
			// 如果是加密数据列表
			else if (obj instanceof PGPEncryptedDataList)
			{
				try
				{
					dataList = (PGPEncryptedDataList) obj;
					Iterator<?> it = dataList.getEncryptedDataObjects();
					PGPPrivateKey sKey = null;
					PGPPublicKeyEncryptedData pbe = null;
					PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
							PGPUtil.getDecoderStream(new FileInputStream(privateKeyFile)),
							new JcaKeyFingerprintCalculator());

					// 获取私钥信息
					while (sKey == null && it.hasNext())
					{
						pbe = (PGPPublicKeyEncryptedData) it.next();
						sKey = findSecretKey(pgpSec, pbe.getKeyID(), passphrase.toCharArray());
					}

					// 如果未找到解密密钥（私钥）抛出异常
					if (sKey == null)
					{
						throw new IllegalArgumentException("Secret key for message not found.");
					}

					InputStream clear = pbe
							.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey));
					JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear);
					Object message = plainFact.nextObject();

					// 如果是压缩数据，则解压数据包
					if (message instanceof PGPCompressedData)
					{
						compressedData = (PGPCompressedData) message;
						pgpFact = new JcaPGPObjectFactory(compressedData.getDataStream());
						message = pgpFact.nextObject();
					}

					// 如果是真实数据，取出数据库并存储文件
					if (message instanceof PGPLiteralData)
					{
						literalData = (PGPLiteralData) message;
						dataInput = literalData.getInputStream();
						fOut = new BufferedOutputStream(new FileOutputStream(outFile));
						Streams.pipeAll(dataInput, fOut);
						dataInput.close();
						fOut.close();
						System.out.println("Message decryption complete.");
					}
					// 如果是签名数据，取出真实数据，并验签数据
					else if (message instanceof PGPOnePassSignatureList)
					{
						signList = (PGPOnePassSignatureList) message;
						handelSignatureList(signList, pgpFact, publicKeyFile, privateKeyFile, passphrase, outFile);
					} else
					{
						throw new PGPException("Message is not a simple encrypted file - type unknown.");
					}
					// 信息完整性检查
					if (pbe.isIntegrityProtected())
					{
						if (!pbe.verify())
						{
							System.err.println("Message failed integrity check.");
						} else
						{
							System.out.println("Message integrity check passed.");
						}
					} else
					{
						System.out.println("No message integrity check.");
					}
				} catch (PGPException e)
				{
					System.err.println(e);
					if (e.getUnderlyingException() != null)
					{
						e.getUnderlyingException().printStackTrace();
					}
				}

			}
			// 如果是签名数据
			else if (obj instanceof PGPOnePassSignatureList)
			{
				signList = (PGPOnePassSignatureList) obj;
				handelSignatureList(signList, pgpFact, publicKeyFile, privateKeyFile, passphrase, outFile);
			}
			// 如果是真实数据，取出数据库并存储文件
			else if (obj instanceof PGPLiteralData)
			{
				literalData = (PGPLiteralData) obj;
				dataInput = literalData.getInputStream();
				fOut = new BufferedOutputStream(new FileOutputStream(outFile));
				Streams.pipeAll(dataInput, fOut);
				dataInput.close();
				fOut.close();
				System.out.println("Message decryption complete.");
			} else
			{
				throw new PGPException("Message is not a simple encrypted file - type unknown.");
			}
		} catch (Exception e)
		{
			e.printStackTrace();
		} finally
		{
			try
			{
				if (fileIn != null)
				{
					fileIn.close();
				}
				if (fOut != null)
				{
					fOut.close();
				}
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}

	}

	/**
	 * 处理签名数据
	 * @param signList
	 * @param pgpFact
	 * @param publicKeyFile
	 * @param privateKeyFile
	 * @param passphrase
	 * @param outFile
	 * @throws Exception
	 * @author Forrest(xiecongshu)
	 * @since 2017年5月17日
	 */
	private void handelSignatureList(PGPOnePassSignatureList signList, JcaPGPObjectFactory pgpFact, File publicKeyFile,
			File privateKeyFile, String passphrase, File outFile) throws Exception
	{
		PGPSignatureList signatureList = null;
		PGPLiteralData literalData = null;
		PGPOnePassSignature ops = null;
		InputStream dataInput = null;
		ops = signList.get(0);
		literalData = (PGPLiteralData) pgpFact.nextObject();
		dataInput = literalData.getInputStream();
		int ch;
		PGPPublicKeyRingCollection pgpRing = new PGPPublicKeyRingCollection(
				PGPUtil.getDecoderStream(new FileInputStream(publicKeyFile)), new JcaKeyFingerprintCalculator());
		PGPPublicKey key = pgpRing.getPublicKey(ops.getKeyID());
		String fileName = "pgp.gpg";
		if(literalData.getFileName() != null && literalData.getFileName().length() > 0){
			fileName = literalData.getFileName();
		}
		FileOutputStream out = new FileOutputStream(fileName);
		ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), key);
		while ((ch = dataInput.read()) >= 0)
		{
			ops.update((byte) ch);
			out.write(ch);
		}
		dataInput.close();
		out.close();

		signatureList = (PGPSignatureList) pgpFact.nextObject();
		if (ops.verify(signatureList.get(0)))
		{
			System.out.println("Signature verified.");
			File tmpFile = new File(fileName);
			decrypt(tmpFile, publicKeyFile, privateKeyFile, passphrase, outFile);
			tmpFile.delete();
		} else
		{
			System.out.println("Signature verification failed.");
		}
	}

	public void encryptAndSign(File srcFile, File outFile, File publicKeyFile, File privateKeyFile, String passphrase,
			boolean armor, boolean withIntegrityCheck) throws Exception
	{
		OutputStream out = null;
		PGPPublicKey pubKey = null;
		try
		{
			out = new FileOutputStream(outFile);
			if (armor)
			{
				out = new ArmoredOutputStream(out);
			}
			
			PGPSecretKey secretKey = readSecretKey(privateKeyFile.getCanonicalPath());
			PGPPrivateKey pgpPrivKey = secretKey.extractPrivateKey(
					new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(passphrase.toCharArray()));
			PGPSignatureGenerator sGen = new PGPSignatureGenerator(
					new JcaPGPContentSignerBuilder(secretKey.getPublicKey().getAlgorithm(), signAlgorithm)
							.setProvider("BC"));
			sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey);
			Iterator<?> it = secretKey.getPublicKey().getUserIDs();
			if (it.hasNext())
			{
				PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
				spGen.setSignerUserID(false, (String) it.next());
				sGen.setHashedSubpackets(spGen.generate());
			}
			FileInputStream fIn = new FileInputStream(srcFile);
			ByteArrayOutputStream bOut = new ByteArrayOutputStream();
			BCPGOutputStream pgpOut = new BCPGOutputStream(bOut);
			sGen.generateOnePassVersion(false).encode(pgpOut);
			PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator();
			OutputStream lOut = lGen.open(pgpOut, PGPLiteralData.BINARY, srcFile);
			int ch;
			while ((ch = fIn.read()) >= 0)
			{
				lOut.write(ch);
				sGen.update((byte) ch);
			}
			fIn.close();
			lGen.close();
			sGen.generate().encode(pgpOut);
			byte [] data = bOut.toByteArray();
			lOut.close();
			pgpOut.close();
			bOut.close();
			
			ByteArrayOutputStream tmpOut = new ByteArrayOutputStream();
			PGPCompressedDataGenerator cDataGen = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);
			OutputStream out1 = cDataGen.open(tmpOut);
			out1.write(data);
			out1.close();
			
			pubKey = readPublicKey(publicKeyFile.getCanonicalPath());
			PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
					new JcePGPDataEncryptorBuilder(encryptAlgorithm).setWithIntegrityPacket(withIntegrityCheck)
							.setSecureRandom(new SecureRandom()).setProvider("BC"));
			encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(pubKey).setProvider("BC"));
			OutputStream eOut = encGen.open(out, tmpOut.toByteArray().length);
			eOut.write(tmpOut.toByteArray());
			tmpOut.close();
			eOut.close();
			out.close();
			System.out.println("EncryptAndSign success.");
		} catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	

	public void encryptFile(File srcFile, File outFile, File publicKeyFile, boolean armor, boolean withIntegrityCheck)
			throws Exception
	{
		OutputStream out = null;
		PGPPublicKey pubKey = null;
		try
		{
			out = new FileOutputStream(outFile);
			if (armor)
			{
				out = new ArmoredOutputStream(out);
			}
			byte[] bytes = compressFile(srcFile.getCanonicalPath(), CompressionAlgorithmTags.ZIP);
			pubKey = readPublicKey(publicKeyFile.getCanonicalPath());
			PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
					new JcePGPDataEncryptorBuilder(encryptAlgorithm).setWithIntegrityPacket(withIntegrityCheck)
							.setSecureRandom(new SecureRandom()).setProvider("BC"));
			encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(pubKey).setProvider("BC"));
			OutputStream cOut = encGen.open(out, bytes.length);
			cOut.write(bytes);
			cOut.close();
			out.close();
			System.out.println("done...");
		} catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * 签名
	 * @param srcFile
	 * @param outFile
	 * @param privateKeyFile
	 * @param passphrase
	 * @param armor
	 * @param withIntegrityCheck
	 * @throws Exception
	 * @author Forrest(xiecongshu)
	 * @since 2017年5月17日
	 */
	public void signFile(File srcFile, File outFile, File privateKeyFile, String passphrase, boolean armor,
			boolean withIntegrityCheck) throws Exception
	{
		OutputStream out = null;
		try
		{
			out = new FileOutputStream(outFile);
			if (armor)
			{
				out = new ArmoredOutputStream(out);
			}
			PGPSecretKey secretKey = readSecretKey(privateKeyFile.getCanonicalPath());
			PGPPrivateKey pgpPrivKey = secretKey.extractPrivateKey(
					new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(passphrase.toCharArray()));
			PGPSignatureGenerator sGen = new PGPSignatureGenerator(
					new JcaPGPContentSignerBuilder(secretKey.getPublicKey().getAlgorithm(), signAlgorithm)
							.setProvider("BC"));
			sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey);
			Iterator<?> it = secretKey.getPublicKey().getUserIDs();
			if (it.hasNext())
			{
				PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
				spGen.setSignerUserID(false, (String) it.next());
				sGen.setHashedSubpackets(spGen.generate());
			}
			PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator(PGPCompressedData.ZLIB);
			BCPGOutputStream bOut = new BCPGOutputStream(cGen.open(out));
			sGen.generateOnePassVersion(false).encode(bOut);

			PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator();
			OutputStream lOut = lGen.open(bOut, PGPLiteralData.BINARY, srcFile);
			FileInputStream fIn = new FileInputStream(srcFile);
			int ch;

			while ((ch = fIn.read()) >= 0)
			{
				lOut.write(ch);
				sGen.update((byte) ch);
			}
			fIn.close();
			lGen.close();

			sGen.generate().encode(bOut);
			cGen.close();
			if (armor)
			{
				out.close();
			}
			System.out.println("done...");
		} catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * 验签
	 * @param input
	 * @param publicKeyFile
	 * @return
	 * @throws Exception
	 * @author Forrest(xiecongshu)
	 * @since 2017年5月17日
	 */
	public boolean verifyFile(File input, File publicKeyFile) throws Exception
	{
		InputStream keyIn = null;
		InputStream in = null;
		try
		{
			keyIn = new FileInputStream(publicKeyFile);
			in = PGPUtil.getDecoderStream(new FileInputStream(input));

			JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(in);

			PGPCompressedData c1 = (PGPCompressedData) pgpFact.nextObject();

			pgpFact = new JcaPGPObjectFactory(c1.getDataStream());

			PGPOnePassSignatureList p1 = (PGPOnePassSignatureList) pgpFact.nextObject();

			PGPOnePassSignature ops = p1.get(0);

			PGPLiteralData p2 = (PGPLiteralData) pgpFact.nextObject();

			InputStream dIn = p2.getInputStream();
			int ch;
			PGPPublicKeyRingCollection pgpRing = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(keyIn),
					new JcaKeyFingerprintCalculator());

			PGPPublicKey key = pgpRing.getPublicKey(ops.getKeyID());
			FileOutputStream out = new FileOutputStream(p2.getFileName());

			ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), key);

			while ((ch = dIn.read()) >= 0)
			{
				ops.update((byte) ch);
				out.write(ch);
			}
			out.close();
			PGPSignatureList p3 = (PGPSignatureList) pgpFact.nextObject();
			
			if (ops.verify(p3.get(0)))
			{
				System.out.println("signature verified.");
				return true;
			} else
			{
				System.out.println("signature verification failed.");
				return false;
			}
		} catch (Exception e)
		{
			e.printStackTrace();
		}finally
		{
			if(in != null){
				in.close();
			}
			if(keyIn != null){
				keyIn.close();
			}
		}
		return false;
	}
	
	public static void main1(String[] args)
	{
		Security.addProvider(new BouncyCastleProvider());
		PGP pgp = new PGP();
		String src = "c:/gpg/8888.txt";
		String distFile = "c:/gpg/1/new.pgp";
		String pgpKeyPath = "c:/gpg/nstc_pgp_key.gpg";
		String pgpKeyPass = "nstc123456";
		String pubPath = "c:/gpg/forrest_gpg_pub.asc";
		pgp.decrypt(new File(distFile), new File(pubPath), new File(pgpKeyPath), pgpKeyPass, new File(src));
		System.out.println("over...");
	}
	
	public static void main(String[] args) throws Exception
	{
		Security.addProvider(new BouncyCastleProvider());
		String srcFile = "c:/gpg/123456.txt";
		String distFile = "c:/gpg/new.pgp";
		String pubPath = "c:/gpg/nstc_pgp_pub.asc";
		String pgpKeyPath = "c:/gpg/forrest_gpg_key.gpg";
		String pgpKeyPass = "123456";
		PGP pgp = new PGP();
		pgp.encryptAndSign(new File(srcFile), new File(distFile), new File(pubPath), new File(pgpKeyPath), pgpKeyPass, true, true);
		System.out.println("over...");
	}
}